"""Model configuration CRUD API endpoints."""

from fastapi import APIRouter, Depends, HTTPException, status
from typing import List, Dict, Any, Optional
from datetime import datetime
from pydantic import BaseModel, Field, validator
import uuid
import logging
from motor.motor_asyncio import AsyncIOMotorDatabase

from ..core.auth import get_current_user
from ..core.database import get_db
from ..models.base import ModelConfig
from ..models.config_manager import ConfigManager

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/v1/model-configs", tags=["model-config"])


class ModelConfigRequest(BaseModel):
    """Request model for creating/updating model configuration."""
    
    name: str = Field(..., min_length=1, max_length=100)
    provider: str = Field(..., min_length=1, max_length=50)
    model_name: str = Field(..., min_length=1)
    api_key: Optional[str] = None
    api_base: Optional[str] = None
    temperature: float = Field(default=0.7, ge=0, le=2)
    max_tokens: int = Field(default=2000, gt=0)
    top_p: float = Field(default=1.0, ge=0, le=1)
    frequency_penalty: float = Field(default=0.0, ge=-2, le=2)
    presence_penalty: float = Field(default=0.0, ge=-2, le=2)
    timeout: int = Field(default=60, gt=0)
    max_retries: int = Field(default=3, ge=0)
    stream: bool = True
    enabled: bool = True
    description: Optional[str] = None
    status: Optional[str] = Field(default="unknown", description="健康状态: healthy, unhealthy, unknown")
    last_checked: Optional[datetime] = None
    provider_config: Dict[str, Any] = Field(default_factory=dict)
    extra_params: Dict[str, Any] = Field(default_factory=dict)
    
    @validator('api_base')
    def validate_api_base(cls, v):
        """Validate API base URL format."""
        if v and not (v.startswith('http://') or v.startswith('https://')):
            raise ValueError('API base must be a valid HTTP(S) URL')
        return v


class ModelConfigResponse(BaseModel):
    """Response model for model configuration."""
    
    id: str
    name: str
    provider: str
    model_name: str
    api_base: Optional[str]
    api_key: Optional[str]  # Masked in response
    temperature: float
    max_tokens: int
    top_p: float
    frequency_penalty: float
    presence_penalty: float
    timeout: int
    max_retries: int
    stream: bool
    enabled: bool
    description: Optional[str]
    status: str = "unknown"  # 健康状态
    last_checked: Optional[datetime] = None
    provider_config: Dict[str, Any]
    extra_params: Dict[str, Any]
    config_version: str
    last_updated: datetime
    created_at: datetime
    created_by: str
    
    class Config:
        json_encoders = {
            datetime: lambda v: v.isoformat()
        }


def mask_api_key(api_key: Optional[str]) -> Optional[str]:
    """Mask API key for security."""
    if not api_key:
        return None
    # 临时禁用掩码，直接返回完整密钥
    return api_key
    # if len(api_key) <= 8:
    #     return "***"
    # return f"{api_key[:4]}...{api_key[-4:]}"


@router.get("/public/demo-models", response_model=List[Dict[str, Any]])
async def get_demo_models(
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> List[Dict[str, Any]]:
    """
    获取演示用的公共模型列表（不需要认证）
    用于头脑风暴等功能

    Returns:
        公共可用的模型列表
    """
    logger.info("=" * 80)
    logger.info("[GET /api/v1/model-configs/public/demo-models] Request received")
    logger.info("=" * 80)

    try:
        # 查询所有启用的模型（不限制user_id）
        logger.info("Querying MongoDB for enabled models...")
        logger.info(f"Query: {{'enabled': True}}")

        configs = []
        count = 0
        async for config in db.model_configs.find({"enabled": True}):
            count += 1
            model_id = config.get("id", str(config.get("_id", "")))
            model_name = config.get("name", "Unknown Model")
            provider = config.get("provider", "unknown")

            logger.info(f"  Found model #{count}: id={model_id}, name={model_name}, provider={provider}")

            configs.append({
                "id": model_id,
                "name": model_name,
                "displayName": config.get("name", config.get("model_name", "Unknown")),
                "provider": provider,
                "providerName": provider,
                "modelName": config.get("model_name", ""),
                "status": config.get("status", "unknown"),
                "isActive": config.get("enabled", False),
                "baseUrl": "",  # 不暴露敏感信息
                "apiKey": "",   # 不暴露敏感信息
            })

        logger.info(f"✅ Successfully retrieved {len(configs)} demo models")
        logger.info(f"Returning response: {[{'id': c['id'], 'name': c['name']} for c in configs]}")
        logger.info("=" * 80)
        return configs

    except Exception as e:
        logger.error(f"❌ Failed to get demo models: {e}")
        logger.error(f"Exception type: {type(e).__name__}")
        import traceback
        logger.error(f"Traceback: {traceback.format_exc()}")
        logger.info("=" * 80)
        return []


@router.get("", response_model=List[ModelConfigResponse])
async def get_model_configs(
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db),
    include_disabled: bool = False
) -> List[ModelConfigResponse]:
    """
    Get all model configurations for the current user.

    Args:
        include_disabled: Include disabled configurations

    Returns:
        List of model configurations
    """
    logger.info("=" * 80)
    logger.info("[GET /api/v1/model-configs] Request received")
    logger.info(f"User ID: {current_user.get('sub', 'N/A')}")
    logger.info(f"Username: {current_user.get('username', 'N/A')}")
    logger.info(f"Include disabled: {include_disabled}")
    logger.info("=" * 80)

    try:
        query = {"user_id": current_user["sub"]}
        if not include_disabled:
            query["enabled"] = True

        logger.info(f"MongoDB query: {query}")
        logger.info("Executing database query...")

        configs = []
        count = 0
        async for config in db.model_configs.find(query):
            count += 1
            config_id = config.get("id", "N/A")
            config_name = config.get("name", "N/A")
            provider = config.get("provider", "N/A")
            enabled = config.get("enabled", False)

            logger.info(f"  Config #{count}: id={config_id}, name={config_name}, provider={provider}, enabled={enabled}")

            config["api_key"] = mask_api_key(config.get("api_key"))
            # 添加缺失的必需字段的默认值
            if "provider_config" not in config:
                config["provider_config"] = {}
            if "extra_params" not in config:
                config["extra_params"] = {}
            configs.append(ModelConfigResponse(**config))

        logger.info(f"✅ Successfully retrieved {len(configs)} model configurations")
        logger.info(f"Response summary: {[{'id': c.id, 'name': c.name, 'provider': c.provider} for c in configs]}")
        logger.info("=" * 80)

        return configs

    except Exception as e:
        logger.error(f"❌ Failed to get model configs: {e}")
        logger.error(f"Exception type: {type(e).__name__}")
        import traceback
        logger.error(f"Traceback: {traceback.format_exc()}")
        logger.info("=" * 80)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve model configurations"
        )


@router.get("/available", response_model=List[Dict[str, Any]])
async def get_available_models_for_chat(
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> List[Dict[str, Any]]:
    """
    获取用户可用的模型列表，用于对话选择
    
    Returns:
        可用于对话的模型配置列表
    """
    try:
        # 只获取启用的配置
        query = {
            "user_id": current_user["sub"],
            "enabled": True
        }
        
        available_models = []
        async for config in db.model_configs.find(query):
            # 转换为前端需要的格式
            model_info = {
                "id": config["id"],
                "name": config.get("name", f"{config['provider']} - {config['model_name']}"),
                "displayName": config.get("name", config["model_name"]),
                "provider": config["provider"],
                "providerName": config["provider"],
                "modelName": config["model_name"],
                "baseUrl": config["api_base"],
                "apiKey": config["api_key"],  # 前端需要完整密钥来调用
                "status": "available",
                "enabled": True,
                "temperature": config.get("temperature", 0.7),
                "maxTokens": config.get("max_tokens", 2000),
                "topP": config.get("top_p", 1.0),
                "stream": config.get("stream", True)
            }
            available_models.append(model_info)
        
        return available_models
        
    except Exception as e:
        logger.error(f"Failed to get available models: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve available models"
        )


@router.get("/{model_id}", response_model=ModelConfigResponse)
async def get_model_config(
    model_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> ModelConfigResponse:
    """
    Get a specific model configuration by ID.
    
    Args:
        model_id: Model configuration ID
    
    Returns:
        Model configuration details
    """
    try:
        config = await db.model_configs.find_one({
            "id": model_id,
            "user_id": current_user["sub"]
        })
        
        if not config:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Model configuration not found"
            )
        
        config["api_key"] = mask_api_key(config.get("api_key"))
        return ModelConfigResponse(**config)
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to get model config {model_id}: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to retrieve model configuration"
        )


@router.post("", response_model=ModelConfigResponse, status_code=status.HTTP_201_CREATED)
async def create_model_config(
    config_request: Dict[str, Any],
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> ModelConfigResponse:
    """
    Create a new model configuration.
    
    Args:
        config_request: Model configuration details
    
    Returns:
        Created model configuration
    """
    try:
        # 提取配置名称
        config_name = config_request.get("displayName") or config_request.get("providerName") or "Unnamed Config"
        
        # Check for duplicate name
        existing = await db.model_configs.find_one({
            "user_id": current_user["sub"],
            "name": config_name
        })
        
        if existing:
            raise HTTPException(
                status_code=status.HTTP_409_CONFLICT,
                detail=f"Configuration with name '{config_name}' already exists"
            )
        
        # Create configuration
        config_id = str(uuid.uuid4())
        now = datetime.utcnow()
        
        config_data = {
            "id": config_id,
            "user_id": current_user["sub"],
            "created_by": current_user.get("username", current_user["sub"]),
            "created_at": now,
            "last_updated": now,
            "config_version": "1.0",
            # 基础配置字段
            "name": config_name,
            "provider": config_request.get("providerId") or config_request.get("provider", "unknown"),
            "model_name": config_request.get("modelName") or config_request.get("model_name", "unknown"),
            "api_key": config_request.get("apiKey"),
            "api_base": config_request.get("baseUrl"),
            "enabled": config_request.get("isActive", True),
            "description": config_request.get("description"),
            "status": config_request.get("status", "unknown"),
            "last_checked": config_request.get("last_checked"),
            # 模型参数
            "temperature": config_request.get("temperature", 0.7),
            "max_tokens": config_request.get("max_tokens", 2000),
            "top_p": config_request.get("top_p", 1.0),
            "frequency_penalty": config_request.get("frequency_penalty", 0.0),
            "presence_penalty": config_request.get("presence_penalty", 0.0),
            "timeout": config_request.get("timeout", 60),
            "max_retries": config_request.get("max_retries", 3),
            "stream": config_request.get("stream", True),
            # 确保这些字段存在
            "provider_config": config_request.get("provider_config", {}),
            "extra_params": config_request.get("extra_params", {})
        }
        
        # Validate configuration
        model_config = ModelConfig(
            api_key=config_data.get("api_key"),
            api_base=config_data.get("api_base"),
            model_name=config_data["model_name"],
            provider=config_data["provider"],
            temperature=config_data["temperature"],
            max_tokens=config_data["max_tokens"]
        )
        model_config.validate()
        
        # Store in database (with full API key)
        await db.model_configs.insert_one(config_data)
        
        # Log configuration creation
        await db.audit_logs.insert_one({
            "user_id": current_user["sub"],
            "action": "create_model_config",
            "resource_id": config_id,
            "resource_type": "model_config",
            "details": {"name": config_name, "provider": config_data["provider"]},
            "timestamp": now
        })
        
        # Return response with masked API key (不修改原始数据)
        response_data = config_data.copy()
        response_data["api_key"] = mask_api_key(response_data.get("api_key"))
        return ModelConfigResponse(**response_data)
        
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception as e:
        logger.error(f"Failed to create model config: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to create model configuration"
        )


@router.put("/{model_id}", response_model=ModelConfigResponse)
async def update_model_config(
    model_id: str,
    config_request: ModelConfigRequest,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> ModelConfigResponse:
    """
    Update an existing model configuration.
    
    Args:
        model_id: Model configuration ID
        config_request: Updated configuration details
    
    Returns:
        Updated model configuration
    """
    try:
        # Check if configuration exists
        existing = await db.model_configs.find_one({
            "id": model_id,
            "user_id": current_user["sub"]
        })
        
        if not existing:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Model configuration not found"
            )
        
        # Check for duplicate name (if name is being changed)
        if config_request.name != existing["name"]:
            duplicate = await db.model_configs.find_one({
                "user_id": current_user["sub"],
                "name": config_request.name,
                "id": {"$ne": model_id}
            })
            
            if duplicate:
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail=f"Configuration with name '{config_request.name}' already exists"
                )
        
        # Update configuration
        now = datetime.utcnow()
        update_data = {
            **config_request.dict(),
            "last_updated": now,
            "config_version": "1.1"  # Increment version
        }
        
        # Validate configuration
        model_config = ModelConfig(
            api_key=update_data.get("api_key"),
            api_base=update_data.get("api_base"),
            model_name=update_data["model_name"],
            provider=update_data["provider"],
            temperature=update_data["temperature"],
            max_tokens=update_data["max_tokens"]
        )
        model_config.validate()
        
        # Update in database
        await db.model_configs.update_one(
            {"id": model_id, "user_id": current_user["sub"]},
            {"$set": update_data}
        )
        
        # Log configuration update
        await db.audit_logs.insert_one({
            "user_id": current_user["sub"],
            "action": "update_model_config",
            "resource_id": model_id,
            "resource_type": "model_config",
            "details": {"name": config_request.name, "changes": list(update_data.keys())},
            "timestamp": now
        })
        
        # Get updated configuration
        updated = await db.model_configs.find_one({"id": model_id})
        updated["api_key"] = mask_api_key(updated.get("api_key"))
        
        return ModelConfigResponse(**updated)
        
    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    except Exception as e:
        logger.error(f"Failed to update model config {model_id}: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to update model configuration"
        )


@router.delete("/{model_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_model_config(
    model_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> None:
    """
    Delete a model configuration.
    
    Args:
        model_id: Model configuration ID
    """
    try:
        # Check if configuration exists
        existing = await db.model_configs.find_one({
            "id": model_id,
            "user_id": current_user["sub"]
        })
        
        if not existing:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Model configuration not found"
            )
        
        # Delete configuration
        await db.model_configs.delete_one({
            "id": model_id,
            "user_id": current_user["sub"]
        })
        
        # Log configuration deletion
        await db.audit_logs.insert_one({
            "user_id": current_user["sub"],
            "action": "delete_model_config",
            "resource_id": model_id,
            "resource_type": "model_config",
            "details": {"name": existing["name"]},
            "timestamp": datetime.utcnow()
        })
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to delete model config {model_id}: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to delete model configuration"
        )


@router.post("/{model_id}/validate", response_model=Dict[str, Any])
async def validate_model_config(
    model_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Dict[str, Any]:
    """
    Validate a model configuration.
    
    Args:
        model_id: Model configuration ID
    
    Returns:
        Validation result
    """
    try:
        config = await db.model_configs.find_one({
            "id": model_id,
            "user_id": current_user["sub"]
        })
        
        if not config:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Model configuration not found"
            )
        
        # Create ModelConfig instance and validate
        model_config = ModelConfig(
            api_key=config.get("api_key"),
            api_base=config.get("api_base"),
            model_name=config["model_name"],
            provider=config.get("provider"),
            temperature=config["temperature"],
            max_tokens=config["max_tokens"],
            top_p=config.get("top_p", 1.0),
            provider_config=config.get("provider_config", {})
        )
        
        try:
            model_config.validate()
            return {
                "valid": True,
                "message": "Configuration is valid"
            }
        except ValueError as e:
            return {
                "valid": False,
                "message": str(e)
            }
            
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to validate model config {model_id}: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to validate model configuration"
        )


@router.post("/{config_id}/check-health", response_model=Dict[str, Any])
async def check_config_health(
    config_id: str,
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Dict[str, Any]:
    """
    Check health status of a specific model configuration using stored credentials.
    This endpoint is used for automatic health checks.
    
    Args:
        config_id: Model configuration ID
    
    Returns:
        Health check result with status and response time
    """
    try:
        from ..models.health_checker import ModelHealthChecker
        
        # 获取配置（包含完整的API key）
        config = await db.model_configs.find_one({
            "id": config_id,
            "user_id": current_user["sub"]
        })
        
        if not config:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Model configuration not found"
            )
        
        # 使用存储的完整API key进行健康检查
        checker = ModelHealthChecker()
        result = await checker.check_model_health(
            base_url=config.get("api_base", ""),
            api_key=config.get("api_key", ""),  # 这里使用的是完整的API key
            model_name=config.get("model_name", ""),
            provider=config.get("provider", "")
        )
        
        # 更新配置状态
        is_available = result.get("status") == "available"
        await db.model_configs.update_one(
            {"id": config_id, "user_id": current_user["sub"]},
            {"$set": {
                "status": "healthy" if is_available else "unhealthy",
                "last_checked": datetime.utcnow()
            }}
        )
        
        # 符合API规范的响应格式
        return {
            "success": is_available,
            "data": {
                "status": "healthy" if is_available else "unhealthy",
                "responseTime": result.get("response_time", 0),
                "modelInfo": {
                    "name": config.get("model_name"),
                    "provider": config.get("provider"),
                    "status": result.get("status")
                }
            },
            "message": result.get("error") if result.get("error") else (
                "Health check passed" if is_available else "Health check failed"
            ),
            "timestamp": datetime.utcnow().isoformat() + "Z"
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to check model health for {config_id}: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Health check failed"
        )


@router.post("/test", response_model=Dict[str, Any])
async def test_model_connection(
    test_request: Dict[str, Any],
    current_user: dict = Depends(get_current_user),
    db: AsyncIOMotorDatabase = Depends(get_db)
) -> Dict[str, Any]:
    """
    Test model API connection.
    
    Args:
        test_request: Contains baseUrl, apiKey, modelName, providerId, configId (optional)
    
    Returns:
        Test result with status and response time
    """
    try:
        from ..models.health_checker import ModelHealthChecker
        
        checker = ModelHealthChecker()
        
        # 获取参数
        config_id = test_request.get("configId")
        base_url = test_request.get("baseUrl", "")
        api_key = test_request.get("apiKey", "")
        model_name = test_request.get("modelName", "")
        provider = test_request.get("providerId", "")
        
        # 如果提供了configId但没有apiKey，从数据库获取完整的API key
        if config_id and not api_key:
            config = await db.model_configs.find_one({
                "id": config_id,
                "user_id": current_user["sub"]
            })
            
            if config:
                # 使用数据库中存储的完整API key
                api_key = config.get("api_key", "")
                # 如果没有提供其他参数，也从数据库获取
                if not base_url:
                    base_url = config.get("api_base", "")
                if not model_name:
                    model_name = config.get("model_name", "")
                if not provider:
                    provider = config.get("provider", "")
            else:
                return {
                    "success": False,
                    "status": "unhealthy",
                    "message": "Configuration not found",
                    "responseTime": 0
                }
        
        # 验证必要参数
        if not base_url or not api_key:
            return {
                "success": False,
                "status": "unhealthy",
                "message": "Missing required parameters: baseUrl and apiKey",
                "responseTime": 0
            }
        
        # 执行健康检查
        result = await checker.check_model_health(
            base_url=base_url,
            api_key=api_key,
            model_name=model_name,
            provider=provider
        )
        
        # 转换为前端期望的格式
        is_available = result.get("status") == "available"
        
        # 如果提供了configId，更新数据库中的状态
        if config_id and is_available:
            await db.model_configs.update_one(
                {"id": config_id, "user_id": current_user["sub"]},
                {"$set": {
                    "status": "healthy" if is_available else "unhealthy",
                    "last_checked": datetime.utcnow()
                }}
            )
        
        # 符合API规范的响应格式
        return {
            "success": is_available,
            "data": {
                "status": "healthy" if is_available else "unhealthy",
                "responseTime": result.get("response_time", 0),
                "modelInfo": {
                    "name": model_name,
                    "provider": provider,
                    "status": result.get("status")
                }
            },
            "message": result.get("error") if result.get("error") else (
                "连接测试成功！模型响应正常。" if is_available else "连接测试失败"
            ),
            "timestamp": datetime.utcnow().isoformat() + "Z"
        }
        
    except Exception as e:
        logger.error(f"Failed to test model connection: {e}")
        # 符合API规范的错误响应格式
        return {
            "success": False,
            "error": {
                "code": "MODEL_TEST_FAILED",
                "message": str(e),
                "details": {},
                "timestamp": datetime.utcnow().isoformat() + "Z",
                "requestId": str(uuid.uuid4())
            }
        }